// *** LICENSE HEADER ***
// Filename: ./engine.cpp
// This file is part of Nodewarz 0.1
// Nodewarz is a 3d OpenGL strategy game
// Copyright (C) 2007 CZestmyr
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// *** END LICENSE HEADER ***
#include "engine.h"

engine::engine(const char* logFile) {
    currentState = GS_NONE;
    toSwitch = GS_MAIN_MENU;
    switchGameState = true;
    run = true;
    timestamp = 0;

    theLogger = new logger(logFile);
    theEventManager = new eventManager();
    theMainMenu = new mainMenu(this);
    theFonts = new fonts(this);
    theGame = new game(this);
    theRoster = new roster(this);
    theConnector = new connector(this);
    theMessageViewer = new messageViewer();

    theConnector->SetEventCallback(engine::NetEventCallback);
}

engine::~engine() {
    delete theLogger;
    delete theEventManager;
    delete theMainMenu;
    delete theFonts;
    delete theGame;
    delete theRoster;
    delete theConnector;
    delete theMessageViewer;
}

bool engine::Init() {
    if (SDL_Init(SDL_INIT_VIDEO)) {
        theLogger->log(LL_ERROR, SDL_GetError());
        return false;
    }
    theLogger->log(LL_INFORMATION, "SDL succesfully initialized");

    SDL_EnableKeyRepeat(500, 40);

    return true;
}

bool engine::SDLCreateWindow() {
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, _BPC);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, _BPC);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, _BPC);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, _BPP);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    if (!SDL_SetVideoMode(_WIDTH, _HEIGHT, _BPP, SDL_OPENGL)) {
        theLogger->log(LL_ERROR, SDL_GetError());
        return false;
    }

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, (GLfloat)_WIDTH / (GLfloat)_HEIGHT, 0.1f, 150.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_TEXTURE_2D);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glDepthFunc(GL_LEQUAL);
    theLogger->log(LL_INFORMATION, "Created window");

    //Font texture loading (has to be done no sooner than OpenGL has been inited)
    theFonts->LoadFonts();

    //The same applies to various gui element textures
    button::LoadTexture();
    canvas::LoadTexture("guiback.png");
    toggle::LoadTexture();

    //Load circle texture for node distance showing
    nodeGraph::LoadTextures();

    resourceList::LoadTextures();
    resource::SetColor();

    return true;
}

void engine::Deinit() {
    resourceList::UnloadTextures();

    nodeGraph::UnloadTextures();

    button::UnloadTexture();
    canvas::UnloadTexture();
    toggle::UnloadTexture();

    theFonts->UnloadFonts();

    theLogger->log(LL_INFORMATION, "Quitting SDL");

    SDL_Quit();
}

bool engine::Run() {
    return run;
}

void engine::Update() {
    Uint32 dt = SDL_GetTicks() - timestamp;
    timestamp += dt;
    fps = (int)(1000.0f / dt);

    if (switchGameState) {
        theLogger->log(LL_INFORMATION, "Switching gamestate");
        //Deinit
        switch (currentState) {
            case GS_MAIN_MENU:
                theMainMenu->UnloadTextures();
                break;
            case GS_GAME:
                theGame->UnloadTextures();
                theGame->EndGame();
                theConnector->Deinit();
                break;
            case GS_ROSTER:
                if (toSwitch != GS_GAME) {
                    theConnector->Deinit();
                    theRoster->DeletePlayerList();
                } else {
                    if (theConnector->IsServer())
                        theRoster->UpdatePlayerColorData();
                }
                theConnector->Close();
                break;
            case GS_NONE:
                break;
        }
        //Init
        switch (toSwitch) {
            case GS_MAIN_MENU:
                theMainMenu->LoadTextures();
                break;
            case GS_GAME:
                theGame->LoadTextures();
                if (currentState == GS_ROSTER)
                    theGame->NewGame(theRoster->GetPlayerList());
                else
                    theGame->NewGame();
                theGame->InitGame();
                theMessageViewer->SetMessageNumber(_MESSAGEVIEWER_NUMBER);
                theMessageViewer->SetTimeout(true);
                theMessageViewer->SetTop(_HEIGHT - 50);
                break;
            case GS_ROSTER:
                theConnector->Open();
                theRoster->NewPlayerList();
                theRoster->Init();
                theMessageViewer->SetMessageNumber(5);
                theMessageViewer->SetTimeout(false);
                theMessageViewer->SetTop(160);
                break;
            case GS_NONE:
                run = false;
                break;
        }
        switchGameState = false;
        currentState = toSwitch;
    }

    switch (currentState) {
        case GS_MAIN_MENU:
            theEventManager->ProcessEvents(theMainMenu);
            break;
        case GS_GAME:
            theEventManager->ProcessEvents(theGame);
            break;
        case GS_ROSTER:
            theEventManager->ProcessEvents(theRoster);
            break;
        default:
            theEventManager->ProcessEvents(NULL);
            break;
    }

    switch (currentState) {
        case GS_MAIN_MENU:
            theMainMenu->Update(dt);
            break;
        case GS_GAME:
            theGame->Update(dt);
            break;
        case GS_ROSTER:
            theRoster->Update(dt);

            break;
    }

    theMessageViewer->Update(dt);
    theConnector->Update(dt);
}

void engine::Draw() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    switch (currentState) {
        case GS_MAIN_MENU:
            theMainMenu->Draw();
            break;
        case GS_ROSTER:
            theRoster->Draw();
            theMessageViewer->Draw(theFonts);
            break;
        case GS_GAME:
            theGame->Draw();
            theMessageViewer->Draw(theFonts);
            break;
    }

    SDL_GL_SwapBuffers();
}

void engine::SwitchState(gamestate state) {
    toSwitch = state;
    switchGameState = true;
}

gamestate engine::GetState(){
    return currentState;
}

int engine::GetFPS() {
    return fps;
}

void engine::Quit() {
    SwitchState(GS_NONE);
}

logger* engine::GetLogger() {
    return theLogger;
}

fonts* engine::GetFonts() {
    return theFonts;
}

game* engine::GetGame() {
    return theGame;
}

connector* engine::GetConnector(){
    return theConnector;
}

roster* engine::GetRoster(){
    return theRoster;
}

messageViewer* engine::GetMessageViewer(){
    return theMessageViewer;
}

void engine::ClientDisconnected(int client){
    if (currentState == GS_ROSTER){
        theRoster->UpdatePlayerControls();
    } else if (currentState == GS_GAME){
        theGame->GetPlayers()->ClaimClientsPlayers(client);
        char buffer[64];
        sprintf(buffer, "automated message: Client %i has disconnected. Server claiming control.", client);
        theConnector->SendMessage(buffer);
    }
}

void engine::ServerDisconnected(){
    if (currentState == GS_GAME){
        theMessageViewer->AddMessage("Server quit. You can continue playing for all players yourself.");
    for (int i = 0; i < 4; ++i)
        theGame->GetPlayers()->ClaimClientsPlayers(i);
    } else if (currentState == GS_ROSTER){
        theRoster->DeinitJoined();
    }
}

void engine::GuiCallback(engine* me, int elementId) {
    //Helper variables
    numberfield* ip1;
    numberfield* ip2;
    numberfield* ip3;
    numberfield* ip4;
    numberfield* port;
    IPaddress addr;
    int i;

    //Test which gui element was pressed and take actions according to this information
    switch (elementId) {
        case _BUTTON_STARTGAME:
            //Also prepare clients for the beginning and send them the startgame event
            me->theRoster->SendPlayerData();
            me->theConnector->PrepareEvent(_CONNECTOR_EVENT_STARTGAME);
            me->theConnector->SendEvent();
            me->SwitchState(GS_GAME);
        break;
        case _BUTTON_BACKTOMENU:
            me->SwitchState(GS_MAIN_MENU);
        break;
        case _BUTTON_SERVERCLIENT:
            me->theConnector->Deinit();
            me->theConnector->SetServer(!me->theConnector->IsServer());
            me->theRoster->ChangeMode();
        break;
        case _BUTTON_CREATE:
            port = (numberfield*)(me->theRoster->GetGui()->GetElement(_BUTTON_IPPORT));
            me->theConnector->SetServer(true);
            if (!me->theConnector->Init(port->GetValue())) {
                me->theRoster->GetGui()->SetElementText("Could not create a server on the given port" , _BUTTON_MSGBAR);
            } else {
                me->theRoster->DeinitCreate();
                me->theRoster->InitCreated();
                me->theRoster->GetGui()->SetElementText("Game created" , _BUTTON_MSGBAR);
                me->theConnector->SendClientList();
                me->theConnector->SendClientNameList();
            }
        break;
        case _BUTTON_CONNECT:
            port = (numberfield*)(me->theRoster->GetGui()->GetElement(_BUTTON_IPPORT));
            ip1 = (numberfield*)(me->theRoster->GetGui()->GetElement(_BUTTON_IP1));
            ip2 = (numberfield*)(me->theRoster->GetGui()->GetElement(_BUTTON_IP2));
            ip3 = (numberfield*)(me->theRoster->GetGui()->GetElement(_BUTTON_IP3));
            ip4 = (numberfield*)(me->theRoster->GetGui()->GetElement(_BUTTON_IP4));
            addr.host = FormatHost(ip1->GetValue(),ip2->GetValue(),ip3->GetValue(),ip4->GetValue());
            addr.port = FormatPort(port->GetValue());
            me->theConnector->SetServer(false);
            if (me->theConnector->Init(0) && me->theConnector->Connect(addr)) {
                me->theRoster->GetGui()->SetElementText("Sent the HI! packet, awaiting server response" , _BUTTON_MSGBAR);
                me->theRoster->DeinitJoin();
                me->theRoster->WaitForResponse();
            } else {
                me->theConnector->Deinit();
                me->theRoster->GetGui()->SetElementText("Could not send HI! packet" , _BUTTON_MSGBAR);
            }
        break;
        case _BUTTON_SENDNAME:
            me->theConnector->SetLocalName(me->theRoster->GetGui()->GetElement(_BUTTON_NAME)->GetText());
            me->theRoster->GetGui()->GetElement(_BUTTON_NICKLABEL)->SetText(me->theRoster->GetGui()->GetElement(_BUTTON_NAME)->GetText());
            if (me->theConnector->IsServer())
                me->theRoster->UpdatePlayerLabels();
        break;
        case _BUTTON_ADD_PLAYER:
            me->theRoster->AddPlayer();
        break;
        case _BUTTON_DELETE_PLAYER:
            me->theRoster->RemovePlayer();
        break;
        case _BUTTON_MESSAGE_LINE:
            if (me->currentState == GS_ROSTER) {
                me->theConnector->SendMessage(me->theRoster->GetGui()->GetElement(_BUTTON_MESSAGE_LINE)->GetText());
                me->theRoster->GetGui()->SetElementText("", _BUTTON_MESSAGE_LINE);
            }
            if (me->currentState == GS_GAME){
                me->theGame->GetGui()->GetElement(_BUTTON_MESSAGE_LINE)->Disable();
                me->theConnector->SendMessage(me->theGame->GetGui()->GetElement(_BUTTON_MESSAGE_LINE)->GetText());
                me->theGame->GetGui()->SetElementText("", _BUTTON_MESSAGE_LINE);
            }
        break;
        case _BUTTON_ENDGAME:
            me->SwitchState(GS_MAIN_MENU);
        break;
        case _BUTTON_ENDTURN:
            if (me->theGame->GetPlayers()->NextPlayer()) {
                me->theConnector->PrepareEvent(_CONNECTOR_EVENT_ENDTURN);
                me->theConnector->SendEvent();
            }
        break;
        case _BUTTON_MODENORMAL:
            me->theGame->GetPlayers()->SetMode(MT_SELECT);
        break;
        case _BUTTON_MODESELECT:
            me->theGame->GetPlayers()->SetMode(MT_ADD_SELECT_CONNECTIONS);
        break;
        case _BUTTON_MODEADD:
            me->theGame->GetPlayers()->SetMode(MT_ADD);
        break;
        case _BUTTON_MODEATTACK:
            me->theGame->GetPlayers()->SetMode(MT_ATTACK);
        break;
        case _BUTTON_MODEDEFEND:
            me->theGame->GetPlayers()->SetMode(MT_DEFEND);
        break;
        case _BUTTON_GAMECONNECT:
            me->theGame->GetPlayers()->ConnectNodesInStack();
            me->theGame->GetPlayers()->SetMode(MT_SELECT);
        break;
        case _BUTTON_MODETAKEOVER:
            me->theGame->GetPlayers()->SetMode(MT_TAKEOVER);
        break;
        case _BUTTON_MODEDISSINTEGRATE:
            me->theGame->GetPlayers()->SetMode(MT_DISSINTEGRATE);
        break;
        case _BUTTON_RESETCAMERA:
            me->theGame->GetCamera()->Reset();
        break;
        default:
            //Player control change buttons
            if ((elementId - _BUTTON_PLAYER_CHANGE - _BUTTON_PLAYER_OFFSET) % _BUTTON_PLAYER_LENGTH == 0 &&
                (elementId - _BUTTON_PLAYER_CHANGE - _BUTTON_PLAYER_OFFSET) / _BUTTON_PLAYER_LENGTH >= 0 &&
                (elementId - _BUTTON_PLAYER_CHANGE - _BUTTON_PLAYER_OFFSET) / _BUTTON_PLAYER_LENGTH < 8) {
                i = (elementId - _BUTTON_PLAYER_CHANGE - _BUTTON_PLAYER_OFFSET) / _BUTTON_PLAYER_LENGTH;
                me->theConnector->SetNextClientNumber(me->theRoster->GetPlayerList()->GetPlayerPointer(i));
                me->theRoster->UpdatePlayerLabels();
            //Kick buttons
            } else if (elementId >= _BUTTON_CLIENT_OFFSET && elementId < _BUTTON_CLIENT_OFFSET + 4) {
                me->theConnector->Disconnect(elementId - _BUTTON_CLIENT_OFFSET);
                me->theRoster->UpdatePlayerControls();
                me->theRoster->UpdatePlayerLabels();
            }
        break;
    }
}

void engine::NetEventCallback(engine* me, const char* messageBuffer){
    //Buffer for the type of the event
    char eventtypeBuffer[6];
    //Buffers for the data of the event
    char dataBuffers[6][13];

    //Some helper variables, used in the "case" construct
    node* aNode;
    node* bNode;
    node* cNode;
    player* eventPlayer;
    player* secondPlayer;
    int helperInteger;

    //Get the event type
    strcpy_safe_my(eventtypeBuffer, messageBuffer + 1, 6);
    int eventType = atoi(eventtypeBuffer);

    //Behave according to the event type
    switch(eventType){
        case _CONNECTOR_EVENT_CLIENTLIST:
            me->theRoster->GetGui()->SetElementText(messageBuffer + 6, _BUTTON_CLIENTLIST);
        break;
        case _CONNECTOR_EVENT_CLIENTNAMELIST:
            me->theRoster->GetGui()->SetElementText(messageBuffer + 6, _BUTTON_NAMELIST);
        break;
        case _CONNECTOR_EVENT_CHANGENAME:
            me->theRoster->UpdatePlayerLabels();
        break;
        case _CONNECTOR_EVENT_PLISTCHANGE:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            me->theRoster->GenerateClientPlayerLabels(atoi(dataBuffers[0]));
        break;
        case _CONNECTOR_EVENT_PDATA:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            strcpy_safe_my(dataBuffers[3], messageBuffer + 42, 13);
            strcpy_safe_my(dataBuffers[4], messageBuffer + 54, 13);
            me->theRoster->SetClientPlayerData(atoi(dataBuffers[0]), atoi(dataBuffers[1]), atoi(dataBuffers[2]), atoi(dataBuffers[3]), atoi(dataBuffers[4]), messageBuffer + 66);
        break;
        case _CONNECTOR_EVENT_STARTGAME:
            me->theRoster->SetClientPlayerList();
            me->SwitchState(GS_GAME);
        break;
        case _CONNECTOR_EVENT_ENDTURN:
            me->theGame->GetPlayers()->NextPlayer(true);
        break;
        case _CONNECTOR_EVENT_CREATENODE:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]))->AddNode(atof(dataBuffers[1]), atof(dataBuffers[2]));
        break;
        case _CONNECTOR_EVENT_CONNECTNODES:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            strcpy_safe_my(dataBuffers[3], messageBuffer + 42, 13);
            strcpy_safe_my(dataBuffers[4], messageBuffer + 54, 13);
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]));
            aNode = eventPlayer->GetClosestNode(atof(dataBuffers[1]), atof(dataBuffers[2]));
            bNode = eventPlayer->GetClosestNode(atof(dataBuffers[3]), atof(dataBuffers[4]));
            eventPlayer->AddConnection(aNode, bNode);
        break;
        case _CONNECTOR_EVENT_PLAYERDATA:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]));
            eventPlayer->SetCredits(atoi(dataBuffers[1]));
        break;
        case _CONNECTOR_EVENT_ATTACK:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            strcpy_safe_my(dataBuffers[3], messageBuffer + 42, 13);
            strcpy_safe_my(dataBuffers[4], messageBuffer + 54, 13);
            strcpy_safe_my(dataBuffers[5], messageBuffer + 66, 13);
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]));
            aNode = eventPlayer->GetClosestNode(atof(dataBuffers[1]), atof(dataBuffers[2]));
            helperInteger = aNode->GetAttackEnergy();
            aNode->ImproveAttack();
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[3]));
            eventPlayer->GetClosestNode(atof(dataBuffers[4]), atof(dataBuffers[5]))->Damage(helperInteger);
            me->theGame->GetParticleSystem()->CreateEmitter(atof(dataBuffers[4]), atof(dataBuffers[5]), 0.0f, 0, _PET_FIRE);
        break;
        case _CONNECTOR_EVENT_DEFEND:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            strcpy_safe_my(dataBuffers[3], messageBuffer + 42, 13);
            strcpy_safe_my(dataBuffers[4], messageBuffer + 54, 13);
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]));
            aNode = eventPlayer->GetClosestNode(atof(dataBuffers[1]), atof(dataBuffers[2]));
            bNode = eventPlayer->GetClosestNode(atof(dataBuffers[3]), atof(dataBuffers[4]));
            helperInteger = aNode->GetDefenceEnergy();
            aNode->ImproveDefence();
            bNode->Defend(helperInteger);
            me->theGame->GetParticleSystem()->CreateEmitter(atof(dataBuffers[3]), atof(dataBuffers[4]), 0.0f, 0, _PET_POWERSPHERE);
        break;
        case _CONNECTOR_EVENT_IMPATTACK:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]));
            aNode = eventPlayer->GetClosestNode(atof(dataBuffers[1]), atof(dataBuffers[2]));
            aNode->ImproveAttack();
        break;
        case _CONNECTOR_EVENT_IMPDEFENCE:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]));
            aNode = eventPlayer->GetClosestNode(atof(dataBuffers[1]), atof(dataBuffers[2]));
            aNode->ImproveDefence();
        break;
        case _CONNECTOR_EVENT_TAKEOVERATTACK:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            strcpy_safe_my(dataBuffers[3], messageBuffer + 42, 13);
            strcpy_safe_my(dataBuffers[4], messageBuffer + 54, 13);
            strcpy_safe_my(dataBuffers[5], messageBuffer + 66, 13);
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]));
            aNode = eventPlayer->GetClosestNode(atof(dataBuffers[1]), atof(dataBuffers[2]));
            secondPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[3]));
            bNode = secondPlayer->GetClosestNode(atof(dataBuffers[4]), atof(dataBuffers[5]));
            if (bNode->EnemyTakeover(aNode->GetTakeoverEnergy())) {
                //Node was taken over by the remote player
                cNode = eventPlayer->AddNode(bNode->GetX(), bNode->GetY());
                cNode->CopyAtributesFrom(bNode);
                cNode->SetTakeoverEnergy(20);
                secondPlayer->RemoveNode(bNode);
            }
            me->theGame->GetParticleSystem()->CreateEmitter(bNode->GetX(), bNode->GetY(), 0.0f, 1, _PET_PSIBURST, aNode->GetX(), aNode->GetY());
        break;
        case _CONNECTOR_EVENT_TAKEOVERDEFENCE:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            strcpy_safe_my(dataBuffers[3], messageBuffer + 42, 13);
            strcpy_safe_my(dataBuffers[4], messageBuffer + 54, 13);
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]));
            aNode = eventPlayer->GetClosestNode(atof(dataBuffers[1]), atof(dataBuffers[2]));
            bNode = eventPlayer->GetClosestNode(atof(dataBuffers[3]), atof(dataBuffers[4]));
            bNode->FriendlyTakeover(aNode->GetTakeoverEnergy());
            me->theGame->GetParticleSystem()->CreateEmitter(aNode->GetX(), aNode->GetY(), 0.0f, 1, _PET_PSIBURST, bNode->GetX(), bNode->GetY());
            aNode->ImproveTakeover();
        break;
        case _CONNECTOR_EVENT_IMPTAKEOVER:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]));
            aNode = eventPlayer->GetClosestNode(atof(dataBuffers[1]), atof(dataBuffers[2]));
            aNode->ImproveTakeover();
        break;
        case _CONNECTOR_EVENT_DISSINTEGRATE:
            strcpy_safe_my(dataBuffers[0], messageBuffer + 6, 13);
            strcpy_safe_my(dataBuffers[1], messageBuffer + 18, 13);
            strcpy_safe_my(dataBuffers[2], messageBuffer + 30, 13);
            eventPlayer = me->theGame->GetPlayers()->GetPlayerPointer(atoi(dataBuffers[0]));
            aNode = eventPlayer->GetClosestNode(atof(dataBuffers[1]), atof(dataBuffers[2]));
            me->theGame->GetParticleSystem()->CreateEmitter(aNode->GetX(), aNode->GetY(), 0.0f, 0, _PET_SMOKE);
            eventPlayer->RemoveNode(aNode);
        break;
    }
}
